{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b5feec22-ac31-4e3d-b486-eae9c8785c49",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 2390 images belonging to 5 classes.\n",
      "Found 539 images belonging to 5 classes.\n",
      "Epoch 1/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m257s\u001b[0m 3s/step - accuracy: 0.2654 - loss: 3.2121 - val_accuracy: 0.3418 - val_loss: 1.3948\n",
      "Epoch 2/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 7ms/step - accuracy: 0.3750 - loss: 0.7176 - val_accuracy: 0.2963 - val_loss: 0.7190\n",
      "Epoch 3/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m251s\u001b[0m 3s/step - accuracy: 0.4182 - loss: 1.3415 - val_accuracy: 0.4316 - val_loss: 1.3380\n",
      "Epoch 4/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 6ms/step - accuracy: 0.1875 - loss: 0.7724 - val_accuracy: 0.5556 - val_loss: 0.5729\n",
      "Epoch 5/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m246s\u001b[0m 3s/step - accuracy: 0.4623 - loss: 1.2939 - val_accuracy: 0.5098 - val_loss: 1.1441\n",
      "Epoch 6/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 6ms/step - accuracy: 0.5312 - loss: 0.6223 - val_accuracy: 0.5556 - val_loss: 0.5457\n",
      "Epoch 7/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m240s\u001b[0m 3s/step - accuracy: 0.5116 - loss: 1.1846 - val_accuracy: 0.6113 - val_loss: 1.0471\n",
      "Epoch 8/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 6ms/step - accuracy: 0.5625 - loss: 0.5936 - val_accuracy: 0.5185 - val_loss: 0.6209\n",
      "Epoch 9/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m242s\u001b[0m 3s/step - accuracy: 0.5037 - loss: 1.1628 - val_accuracy: 0.5664 - val_loss: 1.0748\n",
      "Epoch 10/10\n",
      "\u001b[1m74/74\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 6ms/step - accuracy: 0.5312 - loss: 0.6591 - val_accuracy: 0.4444 - val_loss: 0.6017\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 160ms/step\n",
      "Predicted class: 金属\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n",
    "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
    "# 准备数据集\n",
    "train_data_dir = 'D:/datas/training_data'  # 训练数据文件夹路径\n",
    "validation_data_dir = 'D:/datas/validation_data'  # 验证数据文件夹路径\n",
    "img_width, img_height = 500, 400  # 图像尺寸\n",
    "batch_size = 32\n",
    "# 数据增强和预处理\n",
    "train_datagen = ImageDataGenerator(\n",
    "    rescale=1./255,\n",
    "    shear_range=0.2,\n",
    "    zoom_range=0.2,\n",
    "    horizontal_flip=True)\n",
    "test_datagen = ImageDataGenerator(rescale=1./255)\n",
    "train_generator = train_datagen.flow_from_directory(\n",
    "    train_data_dir,\n",
    "    target_size=(img_width, img_height),\n",
    "    batch_size=batch_size,\n",
    "    class_mode='categorical')\n",
    "validation_generator = test_datagen.flow_from_directory(\n",
    "    validation_data_dir,\n",
    "    target_size=(img_width, img_height),\n",
    "    batch_size=batch_size,\n",
    "    class_mode='categorical')\n",
    "# 定义模型\n",
    "def create_model(input_shape, num_classes):\n",
    "    model = Sequential([\n",
    "        Conv2D(32, (3, 3), activation='relu', input_shape=input_shape),\n",
    "        MaxPooling2D((2, 2)),\n",
    "        Conv2D(64, (3, 3), activation='relu'),\n",
    "        MaxPooling2D((2, 2)),\n",
    "        Conv2D(128, (3, 3), activation='relu'),\n",
    "        MaxPooling2D((2, 2)),\n",
    "        Flatten(),\n",
    "        Dense(128, activation='relu'),\n",
    "        Dropout(0.5),\n",
    "        Dense(num_classes, activation='softmax')\n",
    "    ])\n",
    "    return model\n",
    "# 模型参数\n",
    "input_shape = (img_width, img_height, 3)\n",
    "num_classes = 5  # 有机垃圾、可回收垃圾、有害垃圾和其他垃圾四个类别\n",
    "# 创建模型\n",
    "model = create_model(input_shape, num_classes)\n",
    "# 编译模型\n",
    "model.compile(optimizer='adam',\n",
    "              loss='categorical_crossentropy',\n",
    "              metrics=['accuracy'])\n",
    "# 训练模型\n",
    "epochs = 10\n",
    "history = model.fit(\n",
    "    train_generator,\n",
    "    steps_per_epoch=train_generator.samples // batch_size,\n",
    "    epochs=epochs,\n",
    "    validation_data=validation_generator,\n",
    "    validation_steps=validation_generator.samples // batch_size)\n",
    "# 保存模型\n",
    "model.save('garbage_classifier_model.h5')\n",
    "# 标签映射\n",
    "label_map = {\n",
    "    0: '硬纸板',\n",
    "    1: '玻璃',\n",
    "    2: '金属',\n",
    "    3: '纸张',\n",
    "    4: '塑料',\n",
    "}\n",
    "# 使用模型进行预测\n",
    "def predict_image_class(image_path):\n",
    "    img = tf.keras.preprocessing.image.load_img(image_path, target_size=(img_width, img_height))\n",
    "    img_array = tf.keras.preprocessing.image.img_to_array(img)\n",
    "    img_array = np.expand_dims(img_array, axis=0)  # 添加一个维度作为 batch\n",
    "    predictions = model.predict(img_array)\n",
    "    predicted_class_index = np.argmax(predictions, axis=1)\n",
    "    predicted_class_label = label_map[predicted_class_index[0]]\n",
    "    return predicted_class_label\n",
    "# 示例用法\n",
    "image_path = 'D:/datas/test_image.jpg'\n",
    "predicted_class = predict_image_class(image_path)\n",
    "print('Predicted class:', predicted_class)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "207b0d5b-c212-466d-8acc-846dff167c43",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:absl:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 116ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 49ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 48ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 48ms/step\n"
     ]
    }
   ],
   "source": [
    "import tkinter as tk\n",
    "from tkinter import filedialog, scrolledtext\n",
    "from PIL import Image, ImageTk\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "model = tf.keras.models.load_model('garbage_classifier_model.h5')\n",
    "class GarbageClassifierApp:\n",
    "    def __init__(self, root):\n",
    "        self.root = root\n",
    "        self.root.title(\"Garbage Classifier\")\n",
    "        self.root.geometry(\"800x400\")\n",
    "        # 顶部标签\n",
    "        self.header_label = tk.Label(self.root, text=\"Garbage Classifier\", font=(\"Helvetica\", 16, \"bold\"))\n",
    "        self.header_label.pack(pady=10)\n",
    "        # 图片显示区域\n",
    "        self.image_frame = tk.Frame(self.root, bg=\"lightgray\", width=300, height=300)\n",
    "        self.image_frame.pack(pady=10)\n",
    "        self.image_label = tk.Label(self.image_frame)\n",
    "        self.image_label.pack(padx=10, pady=10)\n",
    "        # 上传图片按钮\n",
    "        self.upload_button = tk.Button(self.root, text=\"上传图片\", command=self.upload_image)\n",
    "        self.upload_button.pack(pady=5)\n",
    "        # 分类结果显示区域\n",
    "        self.result_frame = tk.Frame(self.root)\n",
    "        self.result_frame.pack(pady=10)\n",
    "        self.result_label = tk.Label(self.result_frame, text=\"分类结果:\", font=(\"Helvetica\", 12, \"bold\"))\n",
    "        self.result_label.pack()\n",
    "        self.result_text = scrolledtext.ScrolledText(self.result_frame, wrap=tk.WORD, width=30, height=5)\n",
    "        self.result_text.pack()\n",
    "        # 退出按钮\n",
    "        self.quit_button = tk.Button(self.root, text=\"退出\", command=self.root.destroy)\n",
    "        self.quit_button.pack(pady=5)\n",
    "    def upload_image(self):\n",
    "        # 打开文件对话框，选择图片文件\n",
    "        file_path = filedialog.askopenfilename(filetypes=[(\"Image files\", \"*.jpg;*.jpeg;*.png;*.gif\")])\n",
    "        if file_path:\n",
    "            # 加载并显示所选图片\n",
    "            image = Image.open(file_path)\n",
    "            image = image.resize((300, 300))  # 调整大小以适应界面\n",
    "            photo = ImageTk.PhotoImage(image)\n",
    "            self.image_label.config(image=photo)\n",
    "            self.image_label.image = photo\n",
    "            # 对上传的图片进行分类\n",
    "            predicted_class = self.classify_image(file_path)\n",
    "            self.result_text.insert(tk.END, f\"预测类别: {predicted_class}\\n\")\n",
    "    def classify_image(self, image_path):\n",
    "        # 加载图片并进行预处理\n",
    "        img = Image.open(image_path)\n",
    "        img = img.resize((500, 400))  # 调整大小\n",
    "        img = np.array(img) / 255.0  # 归一化\n",
    "        img = np.expand_dims(img, axis=0)\n",
    "        # 进行分类预测\n",
    "        predictions = model.predict(img)\n",
    "        class_labels = ['硬纸板', '玻璃', '金属', '纸张','塑料']\n",
    "        predicted_class_index = np.argmax(predictions)\n",
    "        predicted_label = class_labels[predicted_class_index]\n",
    "        return predicted_label\n",
    "\n",
    "# 创建主窗口\n",
    "root = tk.Tk()\n",
    "app = GarbageClassifierApp(root)\n",
    "root.mainloop()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dadc04b-f3eb-4a56-bd90-14ecd5f765a1",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
